@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>小王软件</title>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/vue/js/vue.js"></script>
    <script src="~/vue/js/qs.js"></script>
    <script src="~/vue/js/axios.js"></script>
    <script src="~/vue/js/vue-resource.js"></script>
    <script src="~/vue/js/ElementUI/element-ui.js"></script>
    <script src="~/vue/js/ECharts/echarts.min.js"></script>
    <link href="~/vue/css/ElementUI/element-ui.css" rel="stylesheet" />
    <link href="~/vue/css/index.css" rel="stylesheet" />

    <style type="text/css">
        .chat-box {
            height: calc(100vh - 160px);
            overflow-y: auto;
            padding: 10px;
            border-bottom: 1px solid #dcdfe6;
        }

        .input-area {
            display: flex;
            align-items: center;
            margin-top: 10px;
        }

        .message {
            margin: 10px 0;
            display: flex;
            align-items: center;
        }

        .user-message {
            margin-top: 2px;
            display: flex;
            align-items: center;
            margin-left: auto;
        }

        .bot-message {
            margin-top: 2px;
            display: flex;
            align-items: center;
        }

        .reasoning-text {
            font-style: italic;
            color: #555;
            font-size: 12px; /* 设置最小字体大小 */
            background-color: #ffffff; /* 浅灰色背景 */
            color: #555; /* 文字颜色 */
            padding: 4px 8px; /* 内边距 */
            border-radius: 4px; /* 圆角 */
            word-wrap: break-word; /* 长文本换行 */
            white-space: pre-wrap; /* 保留换行符和空格 */
        }

        .content-text {
            font-weight: bold;
        }

        .avatar {
            border-radius: 50%;
            margin-right: 10px;
            width: 50px;
            height: 50px;
        }

        .input-field {
            flex: 1;
            margin-right: 3px;
            max-width: calc(100% - 100px);
        }

        .message-content {
            max-width: 100%; /* 确保消息内容框不超过聊天框宽度 */
            background-color: #f0f0f0; /* 随意选择背景颜色 */
            border-radius: 5px; /* 圆角 */
            padding: 10px; /* 内边距 */
            overflow-wrap: break-word; /* 使长文本换行 */
            white-space: normal; /* 允许文本在标签内换行 */
            word-wrap: break-word; /* 兼容旧版浏览器 */
        }

        .user-message-content {
            background-color: #d1e7dd; /* 用户消息的背景颜色 */
        }

        .bot-message-content {
            background-color: #cfe2ff; /* 机器人消息的背景颜色 */
        }

        .bot-message .el-loading-mask {
            top: 10px;
        }
    </style>

</head>
<body id="main">
    <div id="app">
        <el-container>
            <el-main>
                <el-card>
                    <div class="chat-box" ref="chatBox">
                        <div v-for="(msg, index) in messages" :key="index" class="message">
                            <template v-if="msg.type === 'user'">
                                <div class="user-message">
                                    <div :id="msg.id" class="message-content user-message-content">{{ msg.content }}</div>
                                    <img src="~/img/1.png" alt="User" class="avatar" />
                                </div>
                            </template>
                            <template v-else-if="msg.type === 'bot'">
                                <template v-if="msg.loading">
                                    <div class="bot-message">
                                        <img src="~/img/ai.png" alt="Bot" class="avatar" />
                                        @*<div class="message-content bot-message-content">
                                        正在思考
                                        </div>*@
                                        <div v-loading="loading" element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)"></div>
                                    </div>
                                </template>
                                <template v-else-if="!msg.loading">
                                    <div class="bot-message">
                                        <img src="~/img/ai.png" alt="Bot" class="avatar" />
                                        <div :id="msg.id" class="message-content bot-message-content">
                                            <el-button type="text"
                                                       size="small"
                                                       style="margin-top:-5px;"
                                                       class="el-icon-s-grid"
                                                       @@click="toggleReasoning(msg.id)"
                                                       :disabled="!msg.reasoning"
                                                       :title="reasoningVisibility[msg.id] ? '隐藏推理' : '显示推理'">
                                            </el-button>
                                            <div v-if="!reasoningVisibility[msg.id] && msg.reasoning" class="reasoning-text">{{ msg.reasoning }}</div>
                                            <div class="content-text">
                                                {{ msg.content }}
                                                <i v-if="!speechVisibility[msg.id]" style="color:#67C23A;" class="el-icon-video-play" @@click="speechSynthesis(msg.id,msg.content)"></i>
                                                <i v-if="speechVisibility[msg.id]" style="color:#F56C6C;" class="el-icon-video-pause" @@click="speechStop(msg.id)"></i>
                                            </div>

                                        </div>
                                    </div>
                                </template>
                            </template>
                        </div>
                    </div>
                    <div class="input-area">
                        <el-button size="small" :type="deepThinking ? 'warning' : 'info'" style="margin-right: 3px;" icon="el-icon-cpu" circle title="思考" @@click="toggleDeepThinking"></el-button>
                        @* <el-input v-model="input" placeholder="请输入您的问题..." @@keyup.enter.native="sendMessage" class="input-field" :style="{ maxWidth: 'calc(100% - 100px)' }"></el-input>
                        <el-button type="primary" @@click="sendMessage">发送</el-button> *@
                        <el-input v-model="input" placeholder="请输入您的问题..." @@keyup.enter.native="sendMessage" class="input-field" :style="{ maxWidth: 'calc(100% - 10px)' }">
                            <el-button type="primary" style="color:#66b1ff;margin: -10px -26px;" slot="append" icon="el-icon-position" @@click="sendMessage"></el-button>
                        </el-input>  
                        @* <el-button v-if="listening" style="margin-right: 3px;" size="small" type="success" @@click="startListening" icon="el-icon-microphone" circle title="开启语音"></el-button>
                        <el-button v-if="!listening" style="margin-right: 3px;" size="small" type="danger" @@click="stopListening" icon="el-icon-turn-off-microphone" circle title="关闭语音"></el-button> *@
                        <el-button size="small" type="success" @@click="sendFileMessage" icon="el-icon-upload" circle title="上传文件"></el-button>
                        <input type="file" id="filereader" style="display:none;" @@change="sendFileReader" />
                    </div>
                </el-card>
            </el-main>
        </el-container>
    </div>
</body>
</html>
<script type="text/javascript">
    var vueApp = new Vue({
        el: '#app',
        data() { //定义变量
            return {
                input: '', // 发送消息
                loading: true, // 是否加载
                message: '', // 消息结果
                messages: [], // 消息集合
                websocket: null, // WebSocket对象
                listening: true, // 是否语音
                recognition: null, //语音识别
                deepThinking: false, // 是否开启思考
                speechVisibility: {}, // 是否播放语音
                reasoningVisibility: {}, //是否显示推理内容

            }
        },
        mounted() { //页面初始化
            this.GetWebSocketUrl();
        },
        beforeDestroy() {
            this.closeWebSocket(); // 在组件销毁前关闭WebSocket连接
        },
        methods: { //监听方法
            GetWebSocketUrl() {
                // 获取当前页面的协议（http: 或 https:）
                const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
                // 获取当前域名和端口（例如：localhost:5000 或 meizhouai.wang:5000）
                const host = window.location.host;
                // 构建完整的 WebSocket URL
                const url = `${protocol}${host}/api/WebSocketChat/GetWebSocketReceive`;
                this.initWebSocket(url);
            },
            initWebSocket(url) {
                this.websocket = new WebSocket(url);

                this.websocket.onopen = () => {
                    console.log('WebSocket连接已打开');
                };

                this.websocket.onmessage = (event) => {

                    const messagedata = JSON.parse(event.data);

                    this.message.content += messagedata.Content;

                    this.message.reasoning += messagedata.ReasoningContent;

                    this.message.isReasoningVisible = false;

                    this.message.loading = false;

                    this.loading = false;
                };

                this.websocket.onclose = () => {
                    this.$message({
                        showClose: true,
                        message: '连接已关闭,请稍后重试！',
                        type: 'warning'
                    });
                    this.message.loading = false;
                    this.loading = false;
                    console.log('WebSocket连接已关闭');
                };

                this.websocket.onerror = (event) => {
                    this.$message({
                        showClose: true,
                        message: '服务器繁忙，请稍后重试！',
                        type: 'error'
                    });
                    this.message.loading = false;
                    this.loading = false;
                    console.error('WebSocket发生错误：', event);
                };
            },
            toggleDeepThinking() {
                this.deepThinking = !this.deepThinking;
                this.$message({
                    message: this.deepThinking ? '已开启深度思考模式' : '已关闭深度思考模式',
                    type: this.deepThinking ? 'success' : 'info'
                });
            },
            toggleReasoning(id) {
                const isVisible = this.reasoningVisibility[id];
                this.$set(this.reasoningVisibility, id, isVisible ? false : true);
            },
            guessMimeType(filename) {
                const ext = filename.split('.').pop().toLowerCase();
                switch (ext) {
                    case 'jpg':
                    case 'jpeg':
                        return 'image/jpeg';
                    case 'png':
                        return 'image/png';
                    case 'gif':
                        return 'image/gif';
                    case 'pdf':
                        return 'application/pdf';
                    case 'doc':
                    case 'docx':
                        return 'application/msword';
                    case 'xls':
                    case 'xlsx':
                        return 'application/vnd.ms-excel';
                    case 'txt':
                        return 'text/plain';
                    default:
                        return 'application/octet-stream'; // 未知类型
                }
            },
            sendReader(content, reasoning, arrayBuffer, mimeType) {
                const uint8Array = new Uint8Array(arrayBuffer);
                // 转成 base64（用于传输）
                const base64String = btoa(
                    Array.from(uint8Array).map(b => String.fromCharCode(b)).join('')
                );
                // 构建 JSON 数据对象
                const messageData = {
                    content: content,
                    reasoning: reasoning,
                    fileData: base64String,
                    mimeType: mimeType
                };
                const encoder = new TextEncoder();
                const jsonUtf8 = encoder.encode(JSON.stringify(messageData));
                // 构造长度前缀（大端序）
                const lengthBuffer = new ArrayBuffer(4);
                const lengthView = new DataView(lengthBuffer);
                // false 表示大端序
                lengthView.setUint32(0, jsonUtf8.length, false);

                // 合并：length (4字节) + JSON 数据
                const fullBuffer = new Uint8Array(4 + jsonUtf8.length);
                fullBuffer.set(new Uint8Array(lengthBuffer), 0);
                fullBuffer.set(jsonUtf8, 4);

                this.websocket.send(fullBuffer.buffer);
            },
            sendFileReader() {
                var reader = new FileReader();
                reader.onload = (event) => {
                    const arrayBuffer = event.target.result;
                    const fileInput = document.getElementById("filereader");
                    const file = fileInput.files[0];
                    // 获取文件类型（MIME）
                    const mimeType = file.type || this.guessMimeType(file.name);
                    const Message = { id: Date.now(), reasoning: "", content: this.input, type: 'user', loading: false };
                    this.messages.push(Message);
                    this.scrollToBottom();
                    setTimeout(() => {
                        this.message = { id: Date.now(), reasoning: "", content: "", type: 'bot', loading: true };
                        this.messages.push(this.message);
                        this.scrollToBottom();
                        this.loading = true;
                        this.sendReader(this.input, this.deepThinking, arrayBuffer, mimeType);
                        this.input = '';
                    }, 500);
                };
                var file = document.getElementById("filereader").files[0];
                reader.readAsArrayBuffer(file);
            },
            sendFileMessage() {
                if (this.input.trim() !== '') {

                    document.getElementById('filereader').click();
                }
                else {
                    this.$message({
                        message: '消息不能为空！',
                        type: 'warning'
                    });
                }
            },
            sendMessage() {
                if (this.input.trim() !== '') {
                    const Message = { id: Date.now(), reasoning: "", content: this.input, type: 'user', loading: false };
                    this.messages.push(Message);
                    this.scrollToBottom();
                    // 模拟异步响应
                    setTimeout(() => {
                        this.message = { id: Date.now(), reasoning: "", content: "", type: 'bot', loading: true };
                        this.messages.push(this.message);
                        this.scrollToBottom();
                        this.loading = true;
                        this.sendReader(this.input, this.deepThinking);
                        this.input = '';
                    }, 500); // 延迟0.5秒模拟发送后立即显示“正在思考...”
                }
                else {
                    this.$message({
                        message: '消息不能为空！',
                        type: 'warning'
                    });
                }
            },
            speechSynthesis(id, voice) {
                //检查浏览器是否支持SpeechSynthesis对象
                if (!'speechSynthesis' in window) {
                    this.input = '您的浏览器不支持语音播报功能';
                    return;
                }

                this.speechVisibility[id];
                this.$set(this.speechVisibility, id, true);

                // 创建 SpeechSynthesisUtterance 对象
                var synthesisutterance = new SpeechSynthesisUtterance();

                ////获取并设置话语的语言
                //synthesisutterance.lang

                ////获取并设置话语的音调(值越大越尖锐, 越低越低沉)
                //synthesisutterance.pitch

                ////获取并设置说话的速度(值越大语速越快, 越小语速越慢)
                //synthesisutterance.rate

                //获取并设置说话时的文本
                synthesisutterance.text = voice;

                ////获取并设置说话的声音
                //synthesisutterance.voice

                ////获取并设置说话的音量
                //synthesisutterance.volume

                // 设置语音合成的事件处理函数
                speechSynthesis.speak(synthesisutterance);
                // 开始语音合成
                synthesisutterance.onstart = (event) => {
                    console.log('语音合成开始');
                };

                // 结束语音合成
                synthesisutterance.onend = (event) => {
                    console.log('语音合成结束');
                    this.$set(this.speechVisibility, id, false);
                };

                // 暂停语音合成
                synthesisutterance.onpause = (event) => {
                    console.log('语音合成暂停');
                    this.$set(this.reasoningVisibility, id, false);
                };

                // 恢复语音合成
                synthesisutterance.onresume = (event) => {
                    console.log('语音合成恢复');
                };
                // 分段语音合成
                // synthesisutterance.onboundary = (event) => {
                //     console.log('分段语音合成 ' + event.charIndex);
                // };
            },
            speechStop(id) {
                this.$set(this.speechVisibility, id, false);
                let synthesis = window.speechSynthesis;
                synthesis.cancel();
            },
            startListening() {
                // 初始化 Web Speech API
                var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || null;

                // 检查浏览器是否支持语音识别
                if (!SpeechRecognition) {
                    this.input = '您的浏览器不支持语音识别功能';
                    return;
                }

                this.listening = false;

                // 初始化SpeechRecognition对象
                this.recognition = new SpeechRecognition();

                // 设置属性
                this.recognition.lang = 'zh-CN'; // 设置语言
                this.recognition.interimResults = false; // 是否返回临时结果
                this.recognition.maxAlternatives = 1; // 返回的最大备选结果数

                // 开始监听
                this.recognition.start();

                // 监听'onstart'事件，当语音识别开始时触发
                this.recognition.onstart = (event) => {
                    console.log('语音识别开始');
                };

                // 监听'result'事件，获取语音识别的结果
                this.recognition.onresult = (event) => {
                    const speechResult = event.results[0][0].transcript;
                    this.input = speechResult;
                };

                // 监听'onend'事件，当语音识别结束时触发
                this.recognition.onend = (event) => {
                    this.listening = true;
                    console.log('语音识别结束');
                };

                // 错误处理
                this.recognition.onerror = (event) => {
                    this.listening = true;
                    console.error('语音识别出错：', event.error);
                };
            },
            stopListening() {
                this.listening = true;
                if (this.recognition) {
                    this.recognition.stop();
                }
            },
            closeWebSocket() {
                if (this.websocket) {
                    // 关闭WebSocket连接
                    this.websocket.close();
                }
            },
            delay(time) {
                return new Promise(resolve => setTimeout(resolve, time));
            },
            scrollToBottom() {
                this.$nextTick(() => {
                    this.$refs.chatBox.scrollTop = this.$refs.chatBox.scrollHeight;
                });
            }
        }
    })
</script>
